package com.example.smartwaterapi.config;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.CacheControl;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.ResourceHttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * Web MVC配置
 * 优化版本 - 更好的响应处理和内存使用
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    /**
     * 配置异步请求处理
     */
    @Override
    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
        configurer.setDefaultTimeout(10000); // 从30秒减少到10秒，避免资源占用过长
        configurer.setTaskExecutor(webTaskExecutor());
        configurer.registerCallableInterceptors(new TimeoutCallableProcessingInterceptor(5000)); // 5秒超时拦截器
    }

    /**
     * Web请求异步处理线程池
     * 减少资源占用
     */
    @Bean
    public ThreadPoolTaskExecutor webTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(25);        // 从50减少到25
        executor.setMaxPoolSize(100);        // 从200减少到100
        executor.setQueueCapacity(500);      // 从1000减少到500
        executor.setThreadNamePrefix("web-task-");
        executor.setKeepAliveSeconds(60);
        executor.setRejectedExecutionHandler(new java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy());
        executor.setAllowCoreThreadTimeOut(true); // 允许核心线程回收
        executor.initialize();
        return executor;
    }

    /**
     * 超时拦截器
     */
    public class TimeoutCallableProcessingInterceptor implements org.springframework.web.context.request.async.CallableProcessingInterceptor {
        private final long timeout;
        
        public TimeoutCallableProcessingInterceptor(long timeout) {
            this.timeout = timeout;
        }
        
        @Override
        public <T> Object handleTimeout(org.springframework.web.context.request.NativeWebRequest request, java.util.concurrent.Callable<T> task) {
            return new RuntimeException("处理超时: " + timeout + "ms");
        }
    }

    /**
     * 添加资源处理器
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // 配置静态资源处理和缓存策略
        registry.addResourceHandler("/static/**")
                .addResourceLocations("classpath:/static/")
                .setCacheControl(CacheControl.maxAge(30, TimeUnit.DAYS)
                        .cachePublic());
        
        // 配置Swagger UI资源路径
        registry.addResourceHandler("swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/")
                .setCacheControl(CacheControl.maxAge(1, TimeUnit.DAYS));
                
        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/")
                .setCacheControl(CacheControl.maxAge(7, TimeUnit.DAYS));
                
        // 图片资源缓存时间更长 - 修复路径匹配问题
        registry.addResourceHandler("/images/**")
                .addResourceLocations("classpath:/static/images/")
                .setCacheControl(CacheControl.maxAge(30, TimeUnit.DAYS));
        
        registry.addResourceHandler("/*.jpg")
                .addResourceLocations("classpath:/static/")
                .setCacheControl(CacheControl.maxAge(30, TimeUnit.DAYS));
        
        registry.addResourceHandler("/*.jpeg")
                .addResourceLocations("classpath:/static/")
                .setCacheControl(CacheControl.maxAge(30, TimeUnit.DAYS));
        
        registry.addResourceHandler("/*.png")
                .addResourceLocations("classpath:/static/")
                .setCacheControl(CacheControl.maxAge(30, TimeUnit.DAYS));
        
        registry.addResourceHandler("/*.gif")
                .addResourceLocations("classpath:/static/")
                .setCacheControl(CacheControl.maxAge(30, TimeUnit.DAYS));
        
        registry.addResourceHandler("/*.svg")
                .addResourceLocations("classpath:/static/")
                .setCacheControl(CacheControl.maxAge(30, TimeUnit.DAYS));
                
        // JS和CSS文件缓存 - 修复路径匹配问题
        registry.addResourceHandler("/js/**")
                .addResourceLocations("classpath:/static/js/")
                .setCacheControl(CacheControl.maxAge(7, TimeUnit.DAYS));
        
        registry.addResourceHandler("/css/**")
                .addResourceLocations("classpath:/static/css/")
                .setCacheControl(CacheControl.maxAge(7, TimeUnit.DAYS));
        
        registry.addResourceHandler("/*.js")
                .addResourceLocations("classpath:/static/")
                .setCacheControl(CacheControl.maxAge(7, TimeUnit.DAYS));
        
        registry.addResourceHandler("/*.css")
                .addResourceLocations("classpath:/static/")
                .setCacheControl(CacheControl.maxAge(7, TimeUnit.DAYS));
    }

    /**
     * 添加跨域配置
     * 注意：此方法与CorsConfig类中的配置可能重复，建议使用一种方式
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOriginPatterns("*")
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowedHeaders("*")
                .exposedHeaders("Authorization", "Content-Disposition")
                .allowCredentials(true)
                .maxAge(3600);
    }
    
    /**
     * 优化JSON响应体积
     * 1. 禁用不必要的功能
     * 2. 忽略空值
     * 3. 精简输出
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 创建更省内存的Object Mapper
        ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json()
                .serializationInclusion(JsonInclude.Include.NON_NULL) // 不序列化null值
                .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .featuresToDisable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
                .build();
                
        // 替换默认的JSON转换器
        MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter(objectMapper);
        
        // 添加UTF-8编码的字符串转换器
        StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
        stringConverter.setWriteAcceptCharset(false);  // 提高性能
        
        // 优化资源转换器
        ResourceHttpMessageConverter resourceConverter = new ResourceHttpMessageConverter();
        
        // 先添加自定义转换器
        converters.add(jsonConverter);
        converters.add(stringConverter);
        converters.add(resourceConverter);
    }
} 